#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "list.h"
#include "quantitydelegate.h"
#include "item.h"

#include "listio.h"

#include <QApplication>
#include <QSettings>
#include <QStandardItemModel>
#include <QFileDialog>
#include <QAction>

#include <assert.h>

namespace
{
    static const QString S_LAST_SAVE_DIR("LastSaveDir");
    static const QString S_LAST_OPEN_DIR("LastOpenDir");

    static const QString S_GEOMETRY("Geometry");
    static const QString S_STATE("State");
    static const QString S_RECENT("RecentLists");


    static const QString FILEDIALOG_SAVE_FILTER(QObject::tr("EinkaufsListe (*.xml);;"));
    static const QString FILEDIALOG_OPEN_FILTER(QObject::tr("EinkaufsListe (*.xml);; All Files (*.*)"));
}

MainWindow::MainWindow(QWidget *parent)
:   QMainWindow(parent)
,   ui(new Ui::MainWindow)
,   m_list(NULL)
,   m_file(NULL)
,   m_modified(false)
{
    ui->setupUi(this);

    QSettings::setDefaultFormat(QSettings::IniFormat);

    QSettings s;
    restoreGeometry(s.value(S_GEOMETRY).toByteArray());
    restoreState(s.value(S_STATE).toByteArray());

    ui->recentFilesMenu->setDisabled(true);

    QStringList recent = s.value(S_RECENT).toStringList();
    foreach(const QString &filePath, recent)
        registerRecent(filePath);

    ui->treeView->setDisabled(true);
    ui->frame->setDisabled(true);

    ui->updateAction->setEnabled(false);
    ui->updateAction->setCheckable(true);

    connect(ui->treeView, SIGNAL(itemAppendable(bool))
        , ui->appendItemAction, SLOT(setEnabled(bool)));
    connect(ui->treeView, SIGNAL(itemRemovable(bool))
        , ui->removeItemAction, SLOT(setEnabled(bool)));

    connect(ui->treeView, SIGNAL(webSourceAppendable(bool))
        , ui->appendWebSourceAction, SLOT(setEnabled(bool)));
    connect(ui->treeView, SIGNAL(userSourceAppendable(bool))
        , ui->appendUserSourceAction, SLOT(setEnabled(bool)));
    connect(ui->treeView, SIGNAL(sourceRemovable(bool))
        , ui->removeSourceAction, SLOT(setEnabled(bool)));

    setList(NULL);
}

MainWindow::~MainWindow()
{   
    setList(NULL);

    QSettings s;
    s.setValue(S_GEOMETRY, saveGeometry());
    s.setValue(S_STATE, saveState());
    s.setValue(S_RECENT, QStringList(m_recentActionsByFilePath.keys()));

    delete ui;
}

void MainWindow::setList(
    List *list
,   QFileInfo *file)
{
    stopListUpdate();

    delete m_list;
    delete m_file;

    // TODO stuff when m_list is already set and unsafed...

    m_list = list;
    m_file = file;

    m_modified = false;

    const bool listIsNull(m_list == NULL);
    ui->treeView->setDisabled(listIsNull);
    ui->frame->setDisabled(listIsNull);
    ui->saveAction->setDisabled(listIsNull);
    ui->saveAsAction->setDisabled(listIsNull);

    ui->appendItemAction->setDisabled(true);
    ui->removeItemAction->setDisabled(true);

    ui->appendWebSourceAction->setDisabled(true);
    ui->appendUserSourceAction->setDisabled(true);
    ui->removeSourceAction->setDisabled(true);

    ui->removeUncheckedAction->setDisabled(true);

    if(!m_list)
    {
        list_nameChanged();
        return;
    }

    connect(m_list, SIGNAL(modified())
        , this, SLOT(list_modified()));

    connect(m_list, SIGNAL(nameChanged(const QString&))
        , this, SLOT(list_nameChanged()));

    connect(m_list, SIGNAL(numSourcesChanged(uint))
        , this, SLOT(list_numSourcesChanged(uint)));

    connect(m_list, SIGNAL(updated(uint, uint, uint))
        , this, SLOT(list_updated(uint, uint, uint)));

    list_nameChanged();
    list_numSourcesChanged(m_list->numSources());

    ui->treeView->setList(m_list);
}

void MainWindow::list_nameChanged()
{
    if(!m_list)
        setWindowTitle(QApplication::applicationName());
    else
        setWindowTitle((!m_file || m_modified ? tr("%1 - %2*") : tr("%1 - %2"))
            .arg(QApplication::applicationName()).arg(m_list->name()));
}

void MainWindow::list_numSourcesChanged(uint numSources)
{
    ui->updateAction->setEnabled(numSources > 0);
}

void MainWindow::list_modified()
{
    if(m_modified)
        return;

    setModified(true);
}

void MainWindow::setModified(const bool modified)
{
    if(m_modified == modified)
        return;

    m_modified = modified;
    list_nameChanged();
}

void MainWindow::startListUpdate()
{
    if(!m_list)
    {
        ui->updateAction->setChecked(false);
        return;
    }

    m_list->update();
    ui->updateAction->setChecked(true);
}

void MainWindow::stopListUpdate()
{
    ui->updateAction->setChecked(false);

    if(!m_list)
        return;

    m_list->cancel();
}

void MainWindow::on_updateAction_triggered()
{
    if(m_list->isUpdating())
        stopListUpdate();
    else
        startListUpdate();
}

void MainWindow::list_updated(
    uint succeeded
,   uint failed
,   uint skipped)
{
    assert(m_list);
    assert(!m_list->isUpdating());

    ui->updateAction->setChecked(false);
}

void MainWindow::on_newAction_triggered()
{
    List *list(new List());
    list->setName("New");

    setList(list);
}

void MainWindow::on_exitAction_triggered()
{
    // TODO: check if list needs to be saved...

    close();
}

void MainWindow::on_appendItemAction_triggered()
{
    assert(m_list);

    ui->treeView->createItem();
}

void MainWindow::on_removeItemAction_triggered()
{
    assert(m_list);

    Item *item(ui->treeView->currentItem());
    assert(item);

    m_list->removeItem(item);
}

void MainWindow::on_appendWebSourceAction_triggered()
{
    assert(m_list);

    ui->treeView->createSource();
}

void MainWindow::on_appendUserSourceAction_triggered()
{
    assert(m_list);

    ui->treeView->createSource(false);
}

void MainWindow::on_removeSourceAction_triggered()
{
    assert(m_list);

    Item *item(ui->treeView->currentItem());
    Source *source(ui->treeView->currentSource());

    assert(item);

    item->removeSource(source);
}

void MainWindow::save(QFileInfo *fi)
{
    if(!fi)
    {
        QSettings s;
        const QString openPath(s.value(S_LAST_OPEN_DIR, QApplication::applicationDirPath()).toString());
        const QString path(s.value(S_LAST_SAVE_DIR, openPath).toString());

        const QString fileName = QFileDialog::getSaveFileName(this
            , tr("Save"), path, FILEDIALOG_SAVE_FILTER);

        if(fileName.isEmpty())
            return;

        fi = new QFileInfo(fileName);
        s.setValue(S_LAST_SAVE_DIR, fi->absolutePath());
    }

    if(fi->exists())
    {
        // TODO: Ask for overwrite?
    }

    if(ListIO::store(*fi, *m_list))
    {
        m_file = fi;
        m_list->setName(fi->fileName());

        registerRecent(fi->absoluteFilePath());

        setModified(false);
        return;
    }
    else
    {
        if(m_file == fi)
        {
            delete m_file;
            m_file = NULL;
        }
        else
            delete fi;
    }

    // TODO: Message
}

void MainWindow::open(QFileInfo *fi)
{
    if(!fi)
    {
        QSettings s;
        const QString savePath(s.value(S_LAST_SAVE_DIR, QApplication::applicationDirPath()).toString());
        const QString path(s.value(S_LAST_OPEN_DIR, savePath).toString());

        const QString fileName = QFileDialog::getOpenFileName(this
            , tr("Open"), path, FILEDIALOG_OPEN_FILTER);

        if(fileName.isEmpty())
            return;

        fi = new QFileInfo(fileName);
        s.setValue(S_LAST_OPEN_DIR, fi->absolutePath());
    }

    if(fi->exists())
    {
        List *list = ListIO::restore(*fi);
        if(!list)
        {
            delete fi;
            return;
        }

        setList(list, fi);
        registerRecent(fi->absoluteFilePath());
    }
}

void MainWindow::on_saveAction_triggered()
{
     save(m_file);
}

void MainWindow::on_saveAsAction_triggered()
{
    save(NULL);
}

void MainWindow::on_openAction_triggered()
{
    open(NULL);
}

void MainWindow::registerRecent(const QString &filePath)
{
    QFileInfo fi(filePath);

    if(!fi.exists())
        return;

    if(m_recentActionsByFilePath.contains(filePath))
    {
        ui->recentFilesMenu->removeAction(m_recentActionsByFilePath[filePath]);

        delete m_recentActionsByFilePath[filePath];
        m_recentActionsByFilePath.remove(filePath);
    }

    ui->recentFilesMenu->setEnabled(true);

    QAction *action = new QAction(filePath, ui->recentFilesMenu);

    if(ui->recentFilesMenu->actions().isEmpty())
        ui->recentFilesMenu->insertAction(NULL, action);
    else
        ui->recentFilesMenu->insertAction(ui->recentFilesMenu->actions()[0], action);

    m_recentActionsByFilePath[filePath] = action;
}

void MainWindow::on_recentFilesMenu_triggered(QAction *action)
{
    QFileInfo *fi = new QFileInfo(action->text());
    open(fi);
}
